Jx.categorize('lang.css.selector.compiler', {

	$extend: 'Jx.code.Compiler',

	$helpers: {

		'Arr' : 'Jx.lib.Array'

	},

	$actions: [

		'filter',

		'is',

		'select'

	],

	$$precallback: function(properties, SuperClass){

		var SuperDirectAccess = SuperClass.attrNameDirectAccess,

			MyDirectAccess = properties.attrNameDirectAccess,

			J = Jx;

		if (!J.isObject(MyDirectAccess)){

			MyDirectAccess = properties.attrNameDirectAccess = {};

		}

		if (J.isObject(SuperDirectAccess)){

			J.assignIf(MyDirectAccess, SuperDirectAccess, true);

		}


	},

	parser: 'lang.css.selector.parser',

	indexedIdGenerator: 0,

	trace: true,

	bufferCompiled: true,

	pseudoHandlerPrefix: '__handler_pseudo_',

	hashAttributeName: 'id',

	classAttributeName: 'class',

	hashAttributeOperator: '=',

	classAttributeOperator: '~=',

	nodeQueryIdPrefix: 'q',

	nodeQueryIdAttributeName: '__jx_query_id',

	nodeQueryIndexAttributeName: '__jx_query_index',

	attrNameDirectAccess: {},

	attributeOperatorPriorities: {

		'exists': 1,

		'=': 1,

		'!=': 1,

		'~=': 3,

		'|=': 3

	},

	defaultAttributeOperatorPriority: 2,

	pseudoOperatorPriorities: {

		':root': 4,

		':checked': 4,

		':enabled': 4,

		':disabled': 4,

		':focus': 4,

		':hover': 4,

		':active': 4,

		':link': 4,

		':target': 4,

		':not': 6

	},

	defaultPseudoOperatorPriority: 5,

	nodeDataTypes: [ 1, 3, 4, 5 ],

	validQueryNodeTypes: [ 1, 9 ],

	validQueryNodeType: 1,

	constructor: function(){

		this.$super( arguments );

	},

	onParse: function(o, operation){

		this.$super(arguments);

	},


/**
 * Query				-> Group '$'
 */

	'__parse_Query': function(operation, lexeme, count, groupLex){

		var codes = operation.codes,

			codeBody = [];

		/* register result symbol */
		operation.registerSymbol( 'result', 'false', true );

		/* declare groups code */
		this.declare_GroupSelectors( operation, codeBody );

		operation.addParameter([ 'session', 'node' ]);

		operation.declareSymbols( codes );

		codes[ codes.length ] = codeBody.join("\n");

		/* declare nulls cleanup */
		operation.declareNullSymbols( codes );

		var len = codes.length;

		codes[len++] = 'node = null;';

		codes[len++] = 'return result;';

		/* temporarily flag operation is successful */
		operation.setSuccessful();

		operation.setCompleted();

		/* register function properties */
		var index = operation.nodeInfo,

			names = operation.nodeInfoNames,

			nodeInfoIndex = {};

		operation.setCompiledProperty( 'nodeInfoNames', names );

		operation.setCompiledProperty( 'nodeInfoIndex', nodeInfoIndex );

		for(var name, c=-1, len = names.length; len--;){

			name = names[ ++c ];

			nodeInfoIndex[ name ] = index[name];

		}

	},
/**
 *
 * Group				-> Group ',' Selector
 * 						-> Selector
 *
 */
	'__parse_Group': function(operation, lexeme, count, groupLex, commaLex, selectorLex){

		var groups = operation.__groupSelectors,

			selectorStruct = this.getSelectorStruct( operation );

		/* finalize selector struct codes segment */
		selectorStruct.source = ( count - 1 ? selectorLex : groupLex ).getCode();

		if (!groups){

			operation.__groupSelectors = groups = [];

			operation.__groupSelectorsCount = 0;

		}

		groups[ operation.__groupSelectorsCount++ ] = selectorStruct;

		/* define primary selector */
		var selectors = selectorStruct.simple_selectors,

			primary = selectorStruct.primary_selector = selectors[ selectors.length - 1 ];

		primary.isPrimary = true;

		/* register primary node info */
		operation.currentSelectorNodeInfo = {};

		operation.currentSelectorNodeInfoDefaults = primary.node_info_defaults;

		Jx.each( primary.node_info, this.__callback_RegisterPrimaryNodeInfo, operation );

		/* unlink struct pointer */
		this.purgeSelectorStruct( operation );

	},

/**
 *
 * Selector 			-> Selector Combinator Simple_Selector
 * 						->	Simple_Selector
 *
 */
	'__parse_Selector': function(operation, lexeme, count, selectorLex, combinatorLex, simpleSelectorLex){

		/*
		var struct = this.getSelectorStruct(operation),

			selectors = struct.simple_selectors,

			operators = struct.operators,

			combinator = false,

			simpleStruct = this.getSimpleSelectorStruct(operation);

		// simple selector is at the end item and requires combinator
		if (count > 1){

			combinator = combinatorLex.value;

		} else {

			simpleSelectorLex = selectorLex;

		}

		selectors[ selectors.length ] = simpleStruct;

		simpleStruct.source = simpleSelectorLex.getCode();

		simpleStruct.fullSource = lexeme.getCode();

		operators.unshift( combinator );

		this.purgeSimpleSelectorStruct( operation );

		/**/


	},

/**
 *
 * Simple_Selector	-> Type_Selector Type_Attribute
 * 						-> Type_Selector
 * 						-> Type_Attribute
 *
 */
	'__parse_Simple_Selector': function(operation, lexeme, children, count){

		console.log('simple selector: ', arguments);

		var end = [],

			endCount = 0,

			anchor = 0;

		/* expand type attribute selectors */
		for(var lex, t_children, c = -1, l = count; l--;){

			lex = children[ ++c ];

			if (lex.production == 'Type_Attribute'){

				anchor = c;

				t_children = lex.value;

				endCount += t_children.length;

				end.push.apply(end, t_children);

			} else if ( endCount ){

				end[ endCount++ ] = lex;

			}

		}

		/* insert */
		if (endCount){

			for(; endCount--;){

				children[ anchor + endCount ] = end[ endCount ];

			}

		}

		console.log('new children: ', children);

		/*
		var struct = this.getSimpleSelectorStruct( operation );


		struct.matches.sort( this.__callback_SimpleSelectorSort );

		/**/


	},

/**
 *
 * Type_Selector		-> 'name'
 * 						-> 'name' '|' 'name'
 * 						-> '|' 'name'
 *
 */
	'__parse_Type_Selector': function(operation, lexeme, children, count){

		var nameLex = children[0];

		var nsLex = void(0);

		var ns, name, symbol;

		/* | name */
		if (count == 2) {

			nameLex = children[1];

		/* ns | name */
		} else if (count == 3) {

			nsLex = children[2];

			ns = nsLex.value;

		}

		name = nameLex.value;

		if (nsLex && ns != '*'){

			symbol = operation.setLexemeSymbol( nsLex, 'type_ns_' + ns, {

				params: [ ns ],

				postProcessor: '__code_Match_TypeNs'

			});

			operation.setRequireSymbol( symbol.name, 'get_node_type_ns', {

				postProcessor: '__code_Get_TypeNamespace'

			});

		}

		if (nameLex && name != '*'){

			symbol = operation.setLexemeSymbol( nameLex, 'type_' + name, {

				params: [ name ],

				postProcessor: '__code_Match_Type'

			});

			operation.setRequireSymbol( symbol.name, 'get_node_type', {

				postProcessor: '__code_Get_Type'

			});

		}

		lexeme.priority = 1;

		/*
		if (name != '*'){

			this.setSimpleSelector_Match(

				operation,

				'type('+name+')',

				'__code_Match_Type',

				[ name ],

				1

			);

			this.__process_Require_Type( operation );


			this.setNodeDefaultInfo( operation, 'type', name );

		}

		if (ns != '*'){

			this.setSimpleSelector_Match(

				operation,

				'type_ns('+ns+')',

				'__code_Match_TypeNs',

				[ ns ],

				1

			);

			this.__process_Require_TypeNamespace( operation );

			this.setNodeDefaultInfo( operation, 'type_ns', ns );

		}

		/**/

	},

	'__parse_Type_Attribute': function(operation, lexeme, children, count){

		if (count > 1){

			var current = children[0].value;

			current[ current.length ] = children[1];

			lexeme.replaceChildren = current;

		}

	},

/**
 *
 * Attribute			-> '[' 'name' ']'
 * 						-> '[' 'name' '=' Value ']'
 * 						-> '[' 'name' '*=' Value ']'
 * 						-> '[' 'name' '^=' Value ']'
 * 						-> '[' 'name' '$=' Value ']'
 * 						-> '[' 'name' '~=' Value ']'
 *
 */
	'__parse_Attribute': function(operation, lexeme, children, count){

		var opAndValue = count > 3,

			name = children[1].value,

			operator = 'exists',

			value = '';

		if (opAndValue){

			operator = children[2].value;

			var valueLex = children[3];

			value = valueLex.production == 'string' ?

				valueLex.value

				:

				valueLex.getCode();

		}

		symbol = operation.setLexemeSymbol( lexeme, 'attr_' + name+ '['+ operator + ']'+value, {

			params: [ name, operator, value ],

			postProcessor: '__code_Match_Attribute'

		});

		operation.setRequireSymbol( symbol.name, 'get_attribute_'+name, {

			params: [ name ],

			postProcessor: '__code_Get_Attribute'

		});



		//this.__process_AttributeMatch( operation, name, operator, value );

	},

/**
 *
 * Hash					-> '#' 'name'
 *
 */
	'__parse_Hash': function(operation, lexeme, count, hashChar, hashValue){

		this.__process_AttributeMatch( operation, this.hashAttributeName, this.hashAttributeOperator, hashValue.value );

	},

/**
 *
 * Class					-> '.' 'name'
 *
 */
	'__parse_Class': function(operation, lexeme, count, classChar, classValue){

		this.__process_AttributeMatch( operation, this.classAttributeName, this.classAttributeOperator, classValue.value );

	},

/**
 *
 * Pseudo				-> ':' 'name'
 * 						-> ':' 'name' '(' Value ')'
 * 						-> '::' 'name'
 * 						-> '::' 'name' '(' Value ')'
 */
	'__parse_Pseudo': function(operation, lexeme, count, operatorLex, pseudoLex, openParenthesisLex, valueLex, closeParenthesisLex){

		var delimiter = operatorLex.value,

			pseudoName = pseudoLex.value,

			pseudoIndex = delimiter + pseudoName,

			method = '__code_PseudoMatch['+ pseudoIndex +']',

			value = count > 2 ?

				valueLex.production == 'string' ?

					valueLex.value

					:

					valueLex.getCode()

				:

				'',

			symbolIndex = this.__Str.dirtyToJsVarname( lexeme.getCode() );

		if (method in this){

			var definedPriorities = this.pseudoOperatorPriorities,

				priority = this.defaultPseudoOperatorPriority;

			if (pseudoIndex in definedPriorities){

				priority = definedPriorities[pseudoIndex];

			}

			this[method](

				operation,

				value,

				symbolIndex,

				priority

			);

		} else {

			this.__process_Invalid_Match( operation );

		}

	},

/* Code helpers section */


/* Code helpers section: Intermediate Code Generators */

	'__code_ReturnInvalid': function( operation, nodeVar ){

		return 'false';

	},

	'__code_Is_QueryNode': function( operation, nodeVar, resultVar ){

		var code = '!!' + nodeVar + ' && '+this.__code_Is_QueryNodeType(

			operation,

			'(' + this.__code_Get_NodeType( operation, nodeVar) + ')'

		);

		return resultVar ?

			resultVar + ' = ' + code

			:

			code;

	},

	'__code_Is_NonEmptyNode': function( operation, nodeVar, nodeTypeVar ){

		var codes = [];

		for(var c = -1, type, t = this.nodeDataTypes, l = t.length; l--;){

			codes[ ++c ] = nodeTypeVar + ' == ' + String(type = t[c]);

			if (type == 3){

				codes[ c ] = '('+nodeTypeVar + ' == ' + type + ' && !!' + nodeVar +'.nodeValue)';

			}

		}

		return codes.join(' || ');

	},

	'__code_Is_QueryNodeType': function( operation, nodeTypeVar){

		return nodeTypeVar + ' == ' + this.validQueryNodeType;

	},

	'__code_Get_NodeType': function( operation, nodeVar){

		return nodeVar + '.nodeType';

	},

	'__code_Get_Type': function( operation, nodeVar ){

		return nodeVar + '.nodeName';

	},

	'__code_Get_TypeNamespace': function( operation, nodeVar ){

		/* only supported on some compilers */
		return '"*"';

	},

	'__code_Get_ValidNodeId': function( operation, nodeVar ){

		return operation.registerSymbolIf( 'tempNodeId' );

	},

	'__code_Pre_Get_ValidNodeId': function( operation, nodeVar ){

		return this.__code_Get_NodeQueryIdIf( operation, nodeVar, operation.registerSymbolIf( 'tempNodeId' ) );

	},

	'__code_Get_ParentNode': function( operation, nodeVar){

		return nodeVar + '.parentNode';

	},

	'__code_Get_ValidParentNode': function( operation, nodeVar ){

		var parentNodeVar = operation.registerSymbolIf( 'tempParentNode', null, false, true ),

			nodeTypeVar = operation.registerSymbolIf( 'tempNodeType' );

		return '('+parentNodeVar + ' && '+this.__code_Is_QueryNodeType( operation, nodeTypeVar)+ ' ? '+parentNodeVar+' : null)';

	},

	'__code_Pre_Get_ValidParentNode': function( operation, nodeVar ){

		var parentNodeVar = operation.registerSymbolIf( 'tempParentNode', null, false, true ),

			nodeTypeVar = operation.registerSymbolIf( 'tempNodeType' );

		return parentNodeVar + ' = ' + this.__code_Get_ParentNode( operation, nodeVar )+';' +

			nodeTypeVar + ' = ' + this.__code_Get_NodeType( operation, parentNodeVar )+';';

	},

	'__code_Get_ValidParentNodeId': function ( operation, nodeVar, parentNodeVar){

		return operation.registerSymbolIf( 'tempParentNodeId' );

	},

	'__code_Pre_Get_ValidParentNodeId': function( operation, nodeVar, parentNodeVar){

		var tempParentNodeIdVar = operation.registerSymbolIf( 'tempParentNodeId' );

		return tempParentNodeIdVar+'=null;'

			+ 'if ('+parentNodeVar+'){'

				+ this.__code_Get_NodeQueryIdIf(operation, parentNodeVar, operation.registerSymbolIf( 'tempParentNodeId' ))

			+ '}';
	},

	'__code_Get_FirstChild': function( operation, nodeVar){

		return nodeVar + '.firstChild';

	},

	'__code_Get_LastChild': function( operation, nodeVar){

		return nodeVar + '.lastChild';

	},

	'__code_Get_PreviousSibling': function( operation, nodeVar){

		return nodeVar + '.previousSibling';

	},

	'__code_Get_NextSibling': function( operation, nodeVar){

		return nodeVar + '.nextSibling';

	},

	'__code_Get_Attribute': function( operation, nodeVar, attributeName ){

		var info = this.__helper_Get_AttributeDirectAccessExpression( nodeVar, attributeName );

		return info ?

			info.getter

			:

			nodeVar + '.getAttribute("' + this.__Str.escape(attributeName) + '")';

	},

	'__code_Set_Attribute': function( operation, nodeVar, attributeName, valueExpression ){

		var info = this.__helper_Get_AttributeDirectAccessExpression( nodeVar, attributeName );

		return info ?

			info.setter+ ' = '+valueExpression

			:

			nodeVar + '.setAttribute("' + this.__Str.escape(attributeName) + '", '+valueExpression+')';

	},

	'__code_Get_NodeOwner': function( operation, nodeVar ){

		return nodeVar+'.ownerDocument';

	},


	'__code_Get_NodeOwnerFromSession': function( operation, nodeVar ){

		return operation.registerSessionSymbol( 'owner');

	},

	'__code_Pre_Get_NodeOwnerFromSession': function( operation, nodeVar ){

		var ownerSymbol = operation.registerSessionSymbol( 'owner');

		return 'if (!'+ownerSymbol+'){'+

			ownerSymbol+' = session.owner = '+ this.__code_Get_NodeOwner( operation, nodeVar )+';'+

		'}';

	},

	'__code_Get_RootNode': function( operation, nodeVar, ownerVar ){

		return ownerVar+'.documentElement';

	},

	'__code_Get_RootNodeFromSession': function( operation, nodeVar, ownerVar){

		return operation.registerSessionSymbol( 'root_node');

	},

	'__code_Pre_Get_RootNodeFromSession': function( operation, nodeVar, ownerVar){

		var rootSymbol = operation.registerSessionSymbol( 'root_node');

		return 'if (!'+rootSymbol+'){'+

			rootSymbol+' = session.root_node = '+ this.__code_Get_RootNode( operation, nodeVar, ownerVar )+';'+

		'}';

	},

	'__code_Get_ActiveNode': function( operation, nodeVar, ownerVar){

		/* must implement retrieval of active element in DOM instead of root element */

		return ownerVar+' && '+ownerVar+'.activeElement';//operation.registerSessionSymbol( 'active_node', '', true);

	},

	'__code_Get_ActiveNodeFromSession': function( operation, nodeVar, ownerVar ){

		return operation.registerSessionSymbol( 'active_node');

	},

	'__code_Pre_Get_ActiveNodeFromSession': function( operation, nodeVar, ownerVar ){

		var activeNodeSymbol = operation.registerSessionSymbol( 'active_node');

		return 'if (!'+activeNodeSymbol+'){'+

			activeNodeSymbol+' = session.owner = '+ this.__code_Get_ActiveNode( operation, nodeVar, ownerVar )+';'+

		'}';

	},

	'__code_Get_OwnerAnchorHash': function( operation, nodeVar, ownerVar ){

		/* must implement document url hash in DOM instead of empty string */

		return ownerVar+' && "location" in '+ownerVar+' ? '+ownerVar+'.location.hash : "#"';

	},

	'__code_Get_OwnerHashFromSession': function( operation, nodeVar, ownerVar ){

		return operation.registerSessionSymbol( 'owner_hash' );

	},

	'__code_Pre_Get_OwnerHashFromSession': function( operation, nodeVar, ownerVar ){

		var ownerHashVar = operation.registerSessionSymbol( 'owner_hash');

		return 'if (!'+ownerHashVar+'){'+

			ownerHashVar+' = session.owner = '+ this.__code_Get_OwnerAnchorHash( operation, nodeVar, ownerVar )+';'+

		'}';

	},

	'__code_Get_AncestorNodeInfo': function( operation, nodeVar, nodeIdVar ){

		return 'updatedAncestorNodes['+nodeIdVar+']';

	},

	'__code_Pre_Get_AncestorNodeInfo': function( operation, nodeVar, nodeIdVar ){

		var nodeAncestorStructVar = operation.registerSessionSymbol( 'updatedAncestorNodes', '{}'),

			codes = [],

			codeCount = 0;

		codes[ codeCount++ ] = 'if (!('+nodeIdVar+' in '+nodeAncestorStructVar+')){';

		codes[ codeCount++ ] = this.__code_PopulateAncestorNodeInfo( operation, nodeVar, nodeIdVar, nodeAncestorStructVar );

		codes[ codeCount++ ] = '}';

		return codes.join('\n');

	},

	'__code_Get_NodeLanguageFromNodeInfo': function( operation, nodeVar, infoStructVar ){

		return infoStructVar+'.lang';

	},

	'__code_Get_HoveredNode': function( operation, nodeVar){

		/* must implement retrieval of hovered element in DOM instead of root element */

		return operation.registerSessionSymbol( 'hovered_node', this.__code_Get_GlobalRootNode( operation ), true);

	},

	'__code_Get_NodeQueryIdIf': function(operation, nodeVar, resultVar){

		var codes = [],

			codeCount = 0,

			retrieveIdCode = resultVar + '=' + this.__code_Get_NodeQueryId(operation, nodeVar) + ';';


		codes[ codeCount++ ] = retrieveIdCode;

		/* check if node has id */
		codes[ codeCount++ ] = 'if (!'+resultVar+'){';

		codes[ codeCount++ ] = this.__code_Set_NodeQueryId(operation, nodeVar, '"'+this.nodeQueryIdPrefix+'" + (++compiler.indexedIdGenerator)')+';';

		codes[ codeCount++ ] = retrieveIdCode;

		codes[ codeCount++ ] = '}';

		return codes.join("\n");

	},

	'__code_Get_NodeQueryId': function( operation, nodeVar ){

		return this.__code_Get_Attribute( operation, nodeVar, this.nodeQueryIdAttributeName );

	},

	'__code_Set_NodeQueryId': function( operation, nodeVar, idValueCode ){

		return this.__code_Set_Attribute( operation, nodeVar, this.nodeQueryIdAttributeName, idValueCode );

	},

	'__code_Get_NodeItemIndexAttribute': function( operation, nodeVar){

		return this.__code_Get_Attribute( operation, nodeVar, this.nodeQueryIndexAttributeName );

	},

	'__code_Set_NodeItemIndexAttribute': function( operation, nodeVar, indexVar){

		return this.__code_Set_Attribute( operation, nodeVar, this.nodeQueryIndexAttributeName, indexVar );

	},


	'__code_Get_NodeStruct_Index': function( operation, nodeVar, structInfoVar ){

		return structInfoVar+' ? parseInt('+this.__code_Get_NodeItemIndexAttribute( operation, nodeVar)+', 10) : 1';

	},

	'__code_Get_NodeStruct_Length': function( operation, nodeVar, structInfoVar ){

		return structInfoVar+'.length';

	},

	'__code_Get_NodeStruct_Type_Index': function( operation, nodeVar, structInfoVar, nodeIndexVar ){

		return structInfoVar+'.type_indexes['+nodeIndexVar+']';

	},

	'__code_Get_NodeStruct_Type_Length': function( operation, nodeVar, structInfoVar, nodeIndexVar, typeVar){

		return structInfoVar+'.type_lengths['+typeVar+']';

	},

	'__code_Get_NodeStruct_Reverse_Index': function( operation, nodeVar, indexVar, lengthVar){

		return '('+lengthVar+' - '+indexVar+' + 1)';

	},

	'__code_Pre_Get_NodeStructInfo': function(operation, nodeVar, parentNodeVar, parentNodeId){

		var codes = [],

			codeCount = 0;

		codes[ codeCount++ ] = 'if ('+parentNodeVar+'){';

		codes[ codeCount++ ] = this.__code_PopulateChildNodeInfo( operation, parentNodeVar, parentNodeId )

		codes[ codeCount++ ] = '}';

		return codes.join('\n');

	},

	'__code_Get_NodeStructInfo': function(operation, nodeVar, parentNodeVar, parentNodeId){

		return parentNodeId+' ? updatedChildNodeInfo['+parentNodeId+'] : null';

	},

	'__code_Get_ChildNodeStructInfo': function(operation, nodeVar, nodeId){

		return 'updatedChildNodeInfo['+nodeId+']';

	},

	'__code_Get_ChildNodeStruct_Content_Length': function(operation, nodeVar, structVar){

		return structVar+'.content_length';

	},

	'__code_PopulateChildNodeInfo': function( operation, nodeVar, nodeIdVar ){

		var iterateVar = operation.registerSymbolIf( 'p', null, false, true ),

			nodeInfoStructVar = operation.registerSymbolIf( 'tempNodeStruct', null, false, true ),

			nodeFirstChildCode = this.__code_Get_FirstChild( operation, nodeVar ),

			iterateNextSiblingCode = this.__code_Get_NextSibling( operation, iterateVar ),

			findNodeIndex = this.hasNodeMarkInfo( operation, 'index'),

			findNodeLength = this.hasNodeMarkInfo( operation, 'length'),

			findNodeTypeIndex = this.hasNodeMarkInfo( operation, 'type_index'),

			findNodeTypeLength = this.hasNodeMarkInfo( operation, 'type_length'),

			findContentLength = this.hasNodeMarkInfo( operation, 'content_length'),

			findTypeInfo = findNodeTypeIndex || findNodeTypeLength,

			populateNodeIndex = findNodeIndex || findTypeInfo,

			usesNodeIndexAttribute = findNodeIndex || findTypeInfo,

			updatedChildNodesVar = operation.registerSessionSymbol( 'updatedChildNodeInfo', '{}'),

			indexVar = populateNodeIndex ?

				operation.registerSymbolIf( 'tempNodeIndex')

				:

				false,

			contentIndexVar = this.hasNodeMarkInfo( operation, 'content_length') && operation.registerSymbolIf( 'content_index'),

			typeNameVar = findTypeInfo && operation.registerSymbolIf( 'typeName'),

			typeIndexVar = findTypeInfo && operation.registerSymbolIf( 'tempNodeTypeIndex'),

			tempTypeStructVar = findTypeInfo && operation.registerSymbolIf( 'tempNodeTypeStruct' ),

			nodeTypeVar = operation.registerSymbolIf( 'nodeType'),

			codes = [],

			codeCount = 0,

			nodeStructProperties = [],

			nodeStructPropertyCount = 0;

			if ( indexVar ){

				codes[ codeCount++ ] = indexVar+' = 0;';

			}

			if ( contentIndexVar ){

				codes[ codeCount++ ] = contentIndexVar+' = 0;';

			}

			codes[ codeCount++ ] = this.__code_Get_NodeQueryIdIf( operation, nodeVar, nodeIdVar);

			codes[ codeCount++ ] = 'if (!('+nodeIdVar+' in '+updatedChildNodesVar+')){';

				/* create struct */
				if (findNodeLength){

					nodeStructProperties[ nodeStructPropertyCount++ ] = 'length: 0';

				}

				if (contentIndexVar){

					nodeStructProperties[ nodeStructPropertyCount++ ] = 'content_length: 0';

				}

				if (findTypeInfo){

					if (findNodeTypeIndex){

						nodeStructProperties[ nodeStructPropertyCount++ ] = 'type_indexes: {}';

					}

					if (findNodeTypeLength){

						nodeStructProperties[ nodeStructPropertyCount++ ] = 'type_lengths: {}';

					}

				}

				codes[ codeCount++ ] = nodeInfoStructVar + ' = '+updatedChildNodesVar+'['+nodeIdVar+'] = {';

				codes[ codeCount++ ] = nodeStructProperties.join(',');

				codes[ codeCount++ ] = '}';


				/* iterate */
				if (tempTypeStructVar){

					codes[ codeCount++ ] = findNodeTypeLength ?

						tempTypeStructVar+ ' = '+nodeInfoStructVar+'.type_lengths;'

						:

						tempTypeStructVar+ ' = {};';

				}

				codes[ codeCount++ ] = 'for('+iterateVar+'='+nodeFirstChildCode+'; '+iterateVar+'; '+iterateVar+'='+iterateNextSiblingCode+'){';

					codes[ codeCount++ ] = nodeTypeVar+' = '+this.__code_Get_NodeType( operation, iterateVar )+';';

					if ( contentIndexVar ){

						codes[ codeCount++ ] = 'if (' + this.__code_Is_NonEmptyNode( operation, iterateVar, nodeTypeVar ) + '){';

						codes[ codeCount++ ] = contentIndexVar+'++;';

					}

						if (populateNodeIndex){

							codes[ codeCount++ ] = 'if (' + this.__code_Is_QueryNodeType( operation, nodeTypeVar ) + '){';

								codes[ codeCount++ ] = indexVar+'++;';

								if ( findTypeInfo ){

									codes[ codeCount++ ] = typeNameVar+' = '+this.__code_Get_Type( operation, iterateVar )+';';

									codes[ codeCount++ ] = 'if (!('+ typeNameVar + ' in '+tempTypeStructVar +')){';

										codes[ codeCount++ ] = tempTypeStructVar+'['+typeNameVar+'] = 0;';

									codes[ codeCount++ ] = '}';

									if (findNodeTypeLength){

										codes[ codeCount++ ] = nodeInfoStructVar+'.type_lengths['+typeNameVar+'] = ';

									}

									if (findNodeTypeIndex){

										codes[ codeCount++ ] = nodeInfoStructVar+'.type_indexes['+indexVar+'] = ';

									}

									codes[ codeCount++ ] = '++'+tempTypeStructVar+'['+typeNameVar+'];';

								}

								/* save index info*/
								if (usesNodeIndexAttribute){

									codes[ codeCount++ ] = this.__code_Set_NodeItemIndexAttribute( operation, iterateVar, indexVar) + ';';

								}

							codes[ codeCount++ ] = '}';

						}

					if ( contentIndexVar ){

						codes[ codeCount++ ] = '}';

					}

				/* end for loop */
				codes[ codeCount++ ] = '}';

				if (findNodeLength){

					codes[ codeCount++ ] = nodeInfoStructVar+'.length = '+indexVar+';';

				}

				if ( contentIndexVar ){

					codes[ codeCount++ ] = nodeInfoStructVar+'.content_length = '+contentIndexVar+';';

				}


			codes[ codeCount++ ] = '}';

			return codes.join('\n');



	},

	'__code_PopulateAncestorNodeInfo': function( operation, nodeVar, nodeIdVar, nodeAncestorStructVar ){

		var iterateVar = operation.registerSymbolIf( 'p', null, false, true ),

			nodeInfoStructVar = operation.registerSymbolIf( 'tempNodeStruct', null, false, true ),

			tempNodeIdVar = operation.registerSymbolIf( 'tempNodeId' ),

			nodeTypeVar = operation.registerSymbolIf( 'nodeType'),

			iterateParentNodeVar = this.__code_Get_ParentNode( operation, iterateVar ),

			findLanguage = this.hasNodeMarkInfo( operation, 'node_language'),

			tempAttributeVar = operation.registerSymbolIf( 'tempNodeAttribute' ),

			proceedVar = operation.registerSymbolIf( 'tempProceed'),

			attributeVar = findLanguage && operation.registerSymbolIf( 'tempAttr'),

			emptyNodesLanguageVar = findLanguage && operation.registerSymbolIf( 'tempEmptyLanguageNodes'),

			emptyNodesLanguageCountVar = findLanguage && operation.registerSymbolIf( 'tempEmptyLanguageNodesCount'),

			arrayLengthVar = findLanguage && operation.registerSymbolIf( 'tempArrayLength'),

			codes = [],

			codeCount = 0;

		codes[ codeCount++ ] = proceedVar+' = true;';

		if (findLanguage){

			codes[ codeCount++ ] = emptyNodesLanguageVar+' = [];';

			codes[ codeCount++ ] = emptyNodesLanguageCountVar+' = 0;';

		}

		/* loop ancestors */
		codes[ codeCount++ ] = 'for('+iterateVar+' = '+nodeVar+'; '+iterateVar+' && '+proceedVar+'; '+ iterateVar+' = '+iterateParentNodeVar+'){';

			codes[ codeCount++ ] = nodeTypeVar+' = '+this.__code_Get_NodeType( operation, iterateVar )+';';

			codes[ codeCount++ ] = 'if ('+this.__code_Is_QueryNodeType( operation, nodeTypeVar ) + '){';

				codes[ codeCount++ ] = this.__code_Get_NodeQueryIdIf( operation, iterateVar, tempNodeIdVar);

				codes[ codeCount++ ] = 'if ('+tempNodeIdVar+' in '+nodeAncestorStructVar+'){';

					codes[ codeCount++ ] = proceedVar+' = false;';

				codes[ codeCount++ ] = '} else {';

					codes[ codeCount++ ] = nodeAncestorStructVar+'['+tempNodeIdVar+'] = {};';

				codes[ codeCount++ ] = '}';

				/* start creating language in struct */
				if (findLanguage){

					codes[ codeCount++ ] = 'if ('+proceedVar+'){';

						codes[ codeCount++ ] = nodeAncestorStructVar + '['+tempNodeIdVar+'].lang = ';

							codes[ codeCount++ ] = attributeVar+' = ' + this.__code_Get_Attribute( operation, iterateVar, 'lang' )+' || "";';

					codes[ codeCount++ ] = '} else {';

						codes[ codeCount++ ] = attributeVar+' = ' + nodeAncestorStructVar+'['+tempNodeIdVar+'].lang;';

					codes[ codeCount++ ] = '}';

					codes[ codeCount++ ] = 'if ('+attributeVar+'){';

						codes[ codeCount++ ] = 'for('+arrayLengthVar+' = '+emptyNodesLanguageCountVar+'; '+arrayLengthVar+'--;){';

							codes[ codeCount++ ] = nodeAncestorStructVar+'[ '+emptyNodesLanguageVar+'['+arrayLengthVar+']].lang = '+attributeVar+';';

						codes[ codeCount++ ] = '}';

						codes[ codeCount++ ] = emptyNodesLanguageCountVar+' = 0;';

					codes[ codeCount++ ] = '} else {';

						codes[ codeCount++ ] = emptyNodesLanguageVar+'['+ emptyNodesLanguageCountVar +'++] = '+tempNodeIdVar+';';

					codes[ codeCount++ ] = '}';

				/* end finding language */
				}

			codes[ codeCount++ ] = '}';

		/* end loop ancestors */
		codes[ codeCount++ ] = '}';

		return codes.join('\n');


	},




	'__code_Pre_Get_Simple_Selector_Validator': function( operation, nodeVar, selector ){

		var validatorVar = operation.registerSessionSymbol( 'compiled_selector_'+selector ),

			codes = [],

			codeCount = 0,

			selectorStr = this.__Str.escape(selector);

		codes[ codeCount++ ] = 'if ('+validatorVar+' !== false && !'+validatorVar+'){';

			codes[ codeCount++ ] = validatorVar + ' = session[ "compiled_selector_'+selectorStr+'" ] = compiler.compile("'+selectorStr+'") || false;';

		codes[ codeCount++ ] = '}';



		return codes.join('\n');

	},

	'__code_Get_Simple_Selector_Validator': function( operation, nodeVar, selector ){

		var validatorVar = operation.registerSessionSymbol( 'compiled_selector_'+selector );

		return validatorVar;

	},


	'__code_Pre_Get_Simple_Selector_Validator_Session': function( operation, nodeVar, validatorVar, selector ){

		var sessionVar = operation.registerSessionSymbol( 'selector_session_'+selector ),

			codes = [],

			codeCount = 0,

			selectorStr = this.__Str.escape(selector);

		codes[ codeCount++ ] = 'if ( !'+sessionVar+' ){';

			codes[ codeCount++ ] = sessionVar + ' = '+validatorVar+' ?';

				codes[ codeCount++ ] = '(session[ "selector_session_'+selectorStr+'" ] = compiler.createRunSession('+validatorVar+'))';

				codes[ codeCount++ ] = ':';

				codes[ codeCount++ ] = 'false;';

		codes[ codeCount++ ] = '}';

		return codes.join('\n');

	},

	'__code_Get_Simple_Selector_Validator_Session': function( operation, nodeVar, validatorVar, selector ){

		return operation.registerSessionSymbol( 'selector_session_'+selector );

	},


/* Code helpers section: Type Match */

	'__code_Match_Type': function( operation, nodeVar, typeVar, match){

		return typeVar + ' == "' + this.__Str.escape(match) + '"';

	},

	'__code_Match_TypeNs': function( operation, nodeVar, typeVar, match){

		return typeVar + ' == "' + Str.escape(match) + '"';

	},

/* Code helpers section: Attribute Match */

	/* E[foo] an E element with a "foo" attribute */
	'__code_Match_Attribute[exists]': function( operation, nodeVar, attrVar, operator, value ){

		return attrVar + ' != null';

	},

	/* E[foo="bar"] an E element whose "foo" attribute value is exactly equal to "bar"  */
	'__code_Match_Attribute[=]': function( operation, nodeVar, attrVar, operator, value, isExpression ){

		value = isExpression ?

			'('+ value +')'

			:

			'"' + this.__Str.escape(value) + '"';

		return attrVar + ' == '+value;

	},

	/* E[foo!="bar"] an E element whose "foo" attribute value is not exactly equal to "bar"  */
	'__code_Match_Attribute[!=]': function( operation, nodeVar, attrVar, operator, value, isExpression ){

		value = isExpression ?

			'('+ value +')'

			:

			'"' + this.__Str.escape(value) + '"';

		return attrVar + ' != ' + value;

	},

	/* E[foo~="bar"] an E element whose "foo" attribute value is a list of whitespace-separated values, one of which is exactly equal to "bar" */
	'__code_Match_Attribute[~=]': function( operation, nodeVar, attrVar, operator, value, isExpression ){

		value = isExpression ?

			'" "+('+ value +')+" "'

			:

			'" ' + this.__Str.escape(value) + ' "';

		return attrVar+' && ((" "+'+attrVar + '+" ").indexOf(' + value +') + 1)';

	},

	/* E[foo^="bar"] an E element whose "foo" attribute value begins exactly with the string "bar" */
	'__code_Match_Attribute[^=]': function( operation, nodeVar, attrVar, operator, value, isExpression ){

		value = isExpression ?

			'" "+('+ value +')+" "'

			:

			'" ' + this.__Str.escape(value) + ' "';

		return attrVar+' && !(" "+'+attrVar + '+" ").indexOf(' +value+')';

	},

	/* E[foo$="bar"] an E element whose "foo" attribute value ends exactly with the string "bar" */
	'__code_Match_Attribute[$=]': function( operation, nodeVar, attrVar, operator, value, isExpression ){

		value = isExpression ?

			'('+ value +')'

			:

			'"' + this.__Str.escape(value) + '"';

		return attrVar+' && '+attrVar + '.substring( '+attrVar+'.length - ('+value+').length, '+attrVar+'.length) == ' + value;

	},

	/* E[foo*="bar"] an E element whose "foo" attribute value contains the substring "bar" */
	'__code_Match_Attribute[*=]': function( operation, nodeVar, attrVar, operator, value, isExpression ){

		value = isExpression ?

			'('+ value +')'

			:

			'"' + this.__Str.escape(value) + '"';

		return attrVar+' && ('+attrVar + '.lastIndexOf(' + value + ') + 1)';

	},

	/* E[foo|="en"] an E element whose "foo" attribute has a hyphen-separated list of values beginning (from the left) with "en" */
	'__code_Match_Attribute[|=]': function( operation, nodeVar, attrVar, operator, value, isExpression ){

		value = isExpression ?

			'"-"+('+ value +')+"-"'

			:

			'"-' + this.__Str.escape(value) + '-"';

		return attrVar+' && (("-" + '+attrVar+' + "-").lastIndexOf(' + value + ') + 1)';

	},

	'__code_Match_Attribute[is_visited]': function( operation, hrefAttrVar, visitedAttrVar ){

		return hrefAttrVar+' && '+visitedAttrVar+' == "visited"';

	},

/* Code helpers section: Structural Psuedo Class Match */

	'__code_Match_Is_Child_Node_Struct': function( operation, nodeVar, structInfoVar ){

		return structInfoVar;

	},



	'__code_Match_Nth_Child': function( operation, nodeVar, nodeIndexVar, cycleSize, offset, useType, reverse ){

		var strOffset = offset.toString(),

			strCycleSize = cycleSize.toString();

		if (cycleSize){

			if (!offset){

				return '!('+nodeIndexVar+' % '+strCycleSize+')';

			} else {

				return (

					cycleSize > 0 ?

						nodeIndexVar+' > '+(offset-1).toString()

						:

						nodeIndexVar+' < '+(offset+1).toString()

				) +' && !(('+nodeIndexVar+' - '+strOffset+') % '+strCycleSize+')';

			}

		} else {

			return nodeIndexVar + ' == ' + strOffset;

		}

	},

	'__code_Match_First_Child': function( operation, nodeVar, nodeIndexVar ){

		return '!('+nodeIndexVar+' - 1)';

	},

	'__code_Match_Last_Child': function( operation, nodeVar, nodeIndexVar, nodeLengthVar ){

		return nodeIndexVar+' == '+nodeLengthVar;

	},

	'__code_Match_Only_Child': function( operation, nodeVar, nodeIndexVar, nodeLengthVar ){

		return '!('+nodeLengthVar+'-1) && ('+nodeLengthVar+' == '+nodeIndexVar+')';

	},


/* Code helpers section: Root Node */
	'__code_Match_RootNode': function( operation, nodeVar, rootNodeVar ){

		return nodeVar+' === '+ rootNodeVar;

	},

	'__code_Match_Node_Content_Is_Empty': function( operation, nodeVar, contentLengthVar ){

		return '!'+contentLengthVar;

	},

	'__code_Match_Visited': function( operation, nodeVar, hrefVar, visitedVar){

		return hrefVar+' && '+visitedVar+' == "visited"';

	},

	'__code_Match_Active': function( operation, nodeVar, activeNodeVar ){

		return nodeVar+' === '+activeNodeVar;

	},

	'__code_Match_Target': function( operation, nodeVar, idAttrVar, ownerHashVar ){

		return idAttrVar+' && "#"+'+idAttrVar+' == '+ownerHashVar;

	},

	'__code_Match_Language': function( operation, nodeVar, nodeLanguageVar, value ){

		return this['__code_Match_Attribute[|=]']( operation, nodeVar, nodeLanguageVar, '|=', value );

	},

	'__code_Match_Not_Simple_Selector': function( operation, nodeVar, validatorVar, sessionVar ){

		return validatorVar+' && !'+validatorVar+'('+sessionVar+','+nodeVar+')';

	},

/* Code helpers section: Pseudo Selector Filter - Structural Psuedo Classes */

	/* E:root an E element, root of the document */
	'__code_PseudoMatch[:root]': function( operation, value, symbolIndex, priority ){

		this.setSimpleSelector_Match(

			operation,

			'is_root_node',

			'__code_Match_RootNode',

			[],

			priority,

			null

		);

		this.__process_Require_RootNode( operation );

	},

	/* E:nth-child(n) an E element, the n-th child of its parent */
	'__code_PseudoMatch[:nth-child]': function( operation, value, symbolIndex, priority ){

		return !!value && this.__process_Nth_Child(operation, false, false, value, symbolIndex, priority);

	},

	/* E:nth-last-child(n) an E element, the n-th child of its parent, counting from the last one */
	'__code_PseudoMatch[:nth-last-child]': function( operation, value, symbolIndex, priority ){

		return !!value && this.__process_Nth_Child(operation, false, true, value, symbolIndex, priority);

	},

	/* E:nth-of-type(n) an E element, the n-th sibling of its type */
	'__code_PseudoMatch[:nth-of-type]': function( operation, value, symbolIndex, priority ){

		return !!value && this.__process_Nth_Child(operation, true, false, value, symbolIndex, priority);

	},

	/* E:nth-last-of-type(n) an E element, the n-th sibling of its type, counting from the last one  */
	'__code_PseudoMatch[:nth-last-of-type]': function( operation, value, symbolIndex, priority ){

		return !!value && this.__process_Nth_Child(operation, true, true, value, symbolIndex, priority);

	},


	/* E:first-child an E element, first child of its parent */
	'__code_PseudoMatch[:first-child]': function( operation, value, symbolIndex, priority ){

		return this.__process_First_Child(operation, 'node', false, symbolIndex, priority);

	},

	/* E:last-child an E element, last child of its parent */
	'__code_PseudoMatch[:last-child]': function( operation, value, symbolIndex, priority ){

		return this.__process_Last_Child(operation, 'node', false, symbolIndex, priority);

	},

	/* E:first-of-type an E element, first sibling of its type */
	'__code_PseudoMatch[:first-of-type]': function( operation, value, symbolIndex, priority ){

		return this.__process_First_Child(operation, 'node', true, symbolIndex, priority);

	},

	/* E:last-of-type an E element, last sibling of its type */
	'__code_PseudoMatch[:last-of-type]': function( operation, value, symbolIndex, priority ){

		return this.__process_Last_Child(operation, 'node', true, symbolIndex, priority);

	},

	/* E:only-child an E element, only child of its parent */
	'__code_PseudoMatch[:only-child]': function( operation, value, symbolIndex, priority ){

		return this.__process_Only_Child(operation, 'node', false, symbolIndex, priority);

	},

	/* E:only-of-type an E element, only sibling of its type */
	'__code_PseudoMatch[:only-of-type]': function( operation, value, symbolIndex, priority ){

		return this.__process_Only_Child(operation, 'node', true, symbolIndex, priority);

	},

	/* E:empty an E element that has no children (including text nodes) */
	'__code_PseudoMatch[:empty]': function( operation, value, symbolIndex, priority ){

		this.setSimpleSelector_Match(

			operation,

			'node_is_empty',

			'__code_Match_Node_Content_Is_Empty',

			[],

			priority,

			null

		);

		this.__process_Require_Node_Content_Length( operation );




	},


/* Code helpers section: Pseudo Selector Filter - Link Psuedo Class */

	/* E:link an E element being the source anchor of a hyperlink of which the target is not yet visited (:link) */
	'__code_PseudoMatch[:link]': function( operation, value, symbolIndex, priority ){

		this.__process_AttributeMatch( operation, 'href', 'exists' );

	},

	/* E:visited an E element being the source anchor of a hyperlink of which the target is already visited (:visited) */
	'__code_PseudoMatch[:visited]': function( operation, value, symbolIndex, priority ){

		this.setSimpleSelector_Match(

			operation,

			'node_is_visited',

			'__code_Match_Visited',

			[],

			priority,

			null

		);

		this.__process_Require_Attribute( operation, 'href');

		this.__process_Require_Attribute( operation, 'visited');

	},

/* Code helpers section: Pseudo Selector Filter - User Action Psuedo Classes */

	/* E:active an E element during activate node user action */
	'__code_PseudoMatch[:active]': function( operation, value, symbolIndex, priority ){

		this.setSimpleSelector_Match(

			operation,

			'node_is_active',

			'__code_Match_Active',

			[],

			priority,

			null

		);

		this.__process_Require_ActiveNode( operation );

	},

	/* E:hover an E element during hover node user action */
	'__code_PseudoMatch[:hover]': function( operation, value, symbolIndex, priority ){

	},

	/* E:focus an E element during focus node user action */
	'__code_PseudoMatch[:focus]': function( operation, value, symbolIndex, priority ){

	},


/* Code helpers section: Pseudo Selector Filter - Target Psuedo Class */

	/* E:target an E element being the target of the referring URI */
	'__code_PseudoMatch[:target]': function( operation, value, symbolIndex, priority ){

		this.setSimpleSelector_Match(

			operation,

			'node_is_target',

			'__code_Match_Target',

			[],

			priority,

			null

		);

		this.__process_Require_Attribute( operation, 'id');

		this.__process_Require_OwnerHashUrl( operation );

	},

/* Code helpers section: Pseudo Selector Filter - Language Psuedo Class */

	/* E:lang(fr) an element of type E in language "fr" (the document language specifies how language is determined) */
	'__code_PseudoMatch[:lang]': function( operation, value, symbolIndex, priority ){

		if (value){

			this.setSimpleSelector_Match(

				operation,

				'node_language_is_'+this.__Str.dirtyToJsVarname(value),

				'__code_Match_Language',

				[ value ],

				priority,

				null

			);

			this.__process_Require_NodeLanguage( operation );

		} else {

			this.__process_Invalid_Match( operation );

		}

	},

/* Code helpers section: Pseudo Selector Filter - UI Element States Psuedo Classes */

	/* E:enabled a user interface element E which is enabled */
	'__code_PseudoMatch[:enabled]': function( operation, value, symbolIndex, priority ){

		this.__process_AttributeMatch( operation, 'disabled', '!=', 'disabled' );

	},

	/* E:disabled a user interface element E which is disabled */
	'__code_PseudoMatch[:disabled]': function( operation, value, symbolIndex, priority ){

		this.__process_AttributeMatch( operation, 'disabled', '=', 'disabled' );

	},

	/* E:checked a user interface element E which is checked (for instance a radio-button or checkbox) */
	'__code_PseudoMatch[:checked]': function( operation, value, symbolIndex, priority ){

		this.__process_AttributeMatch( operation, 'checked', '=', 'checked' );

	},

/* Code helpers section: Pseudo Selector Filter - Pseudo Elements Psuedo Classes */

	/* E::first-line the first formatted line of an E element */
	/* E::first-letter the first formatted letter of an E element */
	/* E::before generated content before an E element */
	/* E::after generated content after an E element */

/* Code helpers section: Pseudo Selector Filter - Negation Psuedo Class */

	/* E:not(s) an E element that does not match simple selector s */
	'__code_PseudoMatch[:not]': function( operation, value, symbolIndex, priority ){

		if (value){

			var matchId = this.__Str.dirtyToJsVarname(':not('+value+')');

			this.setSimpleSelector_Match(

				operation,

				matchId,

				'__code_Match_Not_Simple_Selector',

				[ ],

				priority,

				null

			);

			this.__process_Require_Simple_Selector_Validator( operation, value );

		} else {

			this.__process_Invalid_Match( operation );

		}

	},

/* Code helpers section: Combinator Filter */

	/* E F = an F element descendant of an E element */
	'__code_SelectorCombinator[ ]': function( operation, filterCode, source, fullSource ){

		/* find any parent node that gives true result from filterCode */
		var code = [],

			c = 0,

			iteratePointer = operation.createRegisterSymbol( 'iterateP', null, false, true ),

			tempNode = operation.createRegisterSymbol( 'tempNode', null, false, true ),

			nodeIdVar = operation.createRegisterSymbol( 'nodeId' ),

			cachedIdsVar = operation.createRegisterSymbol( 'cachedNodeIds' ),

			cachedIdsCountVar = operation.createRegisterSymbol( 'cachedNodeIdsCount' ),

			firstIterateParentNodeCode = this.__code_Get_ParentNode(operation, 'node'),

			iterateParentNodeCode = this.__code_Get_ParentNode(operation, iteratePointer),

			selectorDescendantCacheVar = operation.registerSessionSymbol( 'ancestor_selectors_' + fullSource, '{}');

		code[ c++ ] = 'result = false;';

		code[ c++ ] = tempNode + ' = node;'

		code[ c++ ] = cachedIdsVar + ' = [];';

		code[ c++ ] = cachedIdsCountVar + ' = 0;';

		code[ c++ ] = 'for('+iteratePointer+' = '+firstIterateParentNodeCode+'; '+iteratePointer+' && !result; '+iteratePointer+' = '+iterateParentNodeCode+' ){';

			code[ c++ ] = 'if ('+this.__code_Is_QueryNode(operation, iteratePointer)+'){';

				code[ c++ ] = 'node = '+iteratePointer+';';

				/* apply caching */
				code[ c++ ] = this.__code_Get_NodeQueryIdIf( operation, iteratePointer, nodeIdVar);

				code[ c++ ] = 'if ('+nodeIdVar+' in '+selectorDescendantCacheVar+'){';

					code[ c++ ] = 'result = '+selectorDescendantCacheVar+'['+nodeIdVar+'];';

					code[ c++ ] = 'break;';

				code[ c++ ] = '} else {';

					code[ c++ ] = filterCode;

					code[ c++ ] = cachedIdsVar + '['+cachedIdsCountVar+'++] = '+nodeIdVar+';';

				code[ c++ ] = '}';
				/* end apply caching */

			code[ c++ ] = '}';

		code[ c++ ] = '}';

		/* finalize cache */
		code[ c++ ] = 'for(;'+cachedIdsCountVar+'--;){';

			code[ c++ ] = selectorDescendantCacheVar+'['+cachedIdsVar+'['+cachedIdsCountVar+']] = result;';

		code[ c++ ] = '}';

		code[ c++ ] = 'node = '+tempNode+';';

		return code.join("\n");

	},


	/* E > F = an F element child of an E element  */
	'__code_SelectorCombinator[ > ]': function( operation, filterCode ){

		/* find any parent node that gives true result from filterCode */
		var code = [],

			c = 0,

			tempNode = operation.createRegisterSymbol( 'tempNode', null, false, true );

		code[ c++ ] = tempNode + ' = node;';

		code[ c++ ] = ' node = '+ this.__code_Get_ParentNode(operation, 'node') + ';';

		code[ c++ ] = 'if (' + this.__code_Is_QueryNode(operation, 'node') + '){';

		code[ c++ ] = filterCode;

		code[ c++ ] = '}';

		code[ c++ ] = 'node = '+tempNode+';';

		return code.join("\n");

	},

	/* E + F = an F element immediately preceded by an E element */
	'__code_SelectorCombinator[ + ]': function( operation, filterCode ){

		/* find any parent node that gives true result from filterCode */
		var code = [],

			c = 0,

			iteratePointer = operation.createRegisterSymbol( 'iterateP', null, false, true ),

			tempNode = operation.createRegisterSymbol( 'tempNode', null, false, true ),

			firstIteratePreviousSiblingCode = this.__code_Get_PreviousSibling( operation, 'node'),

			iteratePreviousSiblingCode = this.__code_Get_PreviousSibling( operation, iteratePointer);

		code[ c++ ] = 'result = false;';

		code[ c++ ] = tempNode + ' = node;';

		code[ c++ ] = 'for('+iteratePointer+' = '+firstIteratePreviousSiblingCode+'; '+iteratePointer+'; '+iteratePointer+' = '+iteratePreviousSiblingCode+' ){';

			code[ c++ ] = 'if ('+ this.__code_Is_QueryNode(operation, iteratePointer)+'){';

				code[ c++ ] = 'node = '+iteratePointer+';';

				code[ c++ ] = filterCode;

				code[ c++ ] = 'break;';

			code[ c++ ] = '}';

		code[ c++ ] = '}';

		code[ c++ ] = 'node = '+tempNode+';';

		return code.join("\n");

	},

	/* E ~ F = an F element preceded by an E element */
	'__code_SelectorCombinator[ ~ ]': function( operation, filterCode ){

		/* find any parent node that gives true result from filterCode */
		var code = [],

			c = 0,

			iteratePointer = operation.createRegisterSymbol( 'iterateP', null, false, true ),

			tempNode = operation.createRegisterSymbol( 'tempNode', null, false, true ),

			firstIteratePreviousSiblingCode = this.__code_Get_PreviousSibling( operation, 'node'),

			iteratePreviousSiblingCode = this.__code_Get_PreviousSibling( operation, iteratePointer);

		code[ c++ ] = 'result = false;';

		code[ c++ ] = tempNode + ' = node;';

		code[ c++ ] = 'for('+iteratePointer+' = '+firstIteratePreviousSiblingCode+'; '+iteratePointer+' && !result; '+iteratePointer+' = '+iteratePreviousSiblingCode+' ){';

			code[ c++ ] = 'if ('+ this.__code_Is_QueryNode(operation, iteratePointer)+' ){';

				code[ c++ ] = 'node = ' + iteratePointer +';';

				code[ c++ ] = filterCode;

			code[ c++ ] = '}';

		code[ c++ ] = '}';

		code[ c++ ] = 'node = '+tempNode+';';

		return code.join("\n");

	},

/* Misc code helpers */


/* Code Processors: Requires */

	'__process_Invalid_Match': function( operation ){

		this.setSimpleSelector_Match(

			operation,

			'node_is_invalid',

			'__code_ReturnInvalid',

			[],

			1

		);

	},

	'__process_Require_Type': function( operation, hidden ){

		var requireId = 'type';

		this.setSimpleSelector_Match_Requirements(

			operation,

			requireId,

			'__code_Get_Type',

			null,

			null,

			null,

			requireId,

			false,

			hidden

		);

		return requireId;

	},

	'__process_Require_TypeNamespace': function( operation, hidden ){

		var requireId = 'type_ns';

		this.setSimpleSelector_Match_Requirements(

			operation,

			requireId,

			'__code_Get_TypeNamespace',

			null,

			null,

			null,

			requireId,

			false,

			hidden

		);

		return requireId;

	},

	'__process_Require_Attribute': function( operation, attributeName, hidden ){

		var requireId = requireId = 'attr_'+attributeName;

		this.setSimpleSelector_Match_Requirements(

			operation,

			requireId,

			'__code_Get_Attribute',

			[ attributeName ],

			null,

			null,

			requireId,

			false,

			hidden

		);

		return requireId;

	},

	'__process_Require_ValidParentNode': function(operation, hidden){

		var requireId = 'parent_node';

		this.setSimpleSelector_Match_Requirements(

			operation,

			requireId,

			'__code_Get_ValidParentNode',

			[ ],

			null,

			'__code_Pre_Get_ValidParentNode',

			requireId,

			true,

			hidden

		);

		return requireId;

	},

	'__process_Require_ValidParentNodeId': function( operation, hidden ){

		var requireParentNode = this.__process_Require_ValidParentNode(operation, true),

			requireId = 'parent_node_id';

		this.setSimpleSelector_Match_Requirements(

			operation,

			requireId,

			'__code_Get_ValidParentNodeId',

			null,

			[ requireParentNode ],

			'__code_Pre_Get_ValidParentNodeId',

			requireId,

			true,

			hidden

		);

		return requireId;


	},

	'__process_Require_NodeStructInfo': function( operation, hidden ){

		var requireParentNode = this.__process_Require_ValidParentNode(operation, true),

			requireParentNodeId = this.__process_Require_ValidParentNodeId(operation, true),

			requireId = 'node_struct_info';

		this.setSimpleSelector_Match_Requirements(

			operation,

			requireId,

			'__code_Get_NodeStructInfo',

			null,

			[ requireParentNode, requireParentNodeId ],

			'__code_Pre_Get_NodeStructInfo',

			null,

			true,

			hidden !== false

		);

		return requireId;

	},

	'__process_Require_ValidNodeId': function( operation, hidden ){

		var requireId = 'node_id';

		this.setSimpleSelector_Match_Requirements(

			operation,

			requireId,

			'__code_Get_ValidNodeId',

			null,

			[],

			'__code_Pre_Get_ValidNodeId',

			requireId,

			true,

			hidden

		);

		return requireId;

	},

	'__process_Require_NodeStruct_Index_Base': function( operation, hidden ){

		var infoRequireId = this.__process_Require_NodeStructInfo( operation ),

			requireId = 'node_struct_index';

		this.setNodeMarkInfo( operation, 'index');

		this.setSimpleSelector_Match_Requirements(

			operation,

			requireId,

			'__code_Get_NodeStruct_Index',

			null,

			[ infoRequireId ],

			null,

			requireId,

			false,

			hidden

		);

		return requireId;

	},

	'__process_Require_NodeStruct_Length_Base': function( operation, hidden ){

		var infoRequireId = this.__process_Require_NodeStructInfo( operation ),

			requireId = 'node_struct_length';

		this.setNodeMarkInfo( operation, 'length');

		this.setSimpleSelector_Match_Requirements(

			operation,

			requireId,

			'__code_Get_NodeStruct_Length',

			null,

			[ infoRequireId ],

			null,

			requireId,

			false,

			hidden

		);

		return requireId;

	},

	'__process_Require_NodeStruct_Index': function( operation, ofType, hidden ){

		var infoRequireId = this.__process_Require_NodeStructInfo( operation ),

			requireId = this.__process_Require_NodeStruct_Index_Base( operation, true ),

			requireId;

		/* get node index by type */
		if (ofType){

			var indexRequireId = this.__process_Require_NodeStruct_Index_Base( operation, true );

			requireId = 'node_struct_type_index';

			this.setNodeMarkInfo( operation, 'type_index');

			this.setSimpleSelector_Match_Requirements(

				operation,

				requireId,

				'__code_Get_NodeStruct_Type_Index',

				null,

				[ infoRequireId, indexRequireId ],

				null,

				requireId,

				false,

				hidden
			);

			return requireId;

		} else {

			return this.__process_Require_NodeStruct_Index_Base( operation, hidden );

		}

	},

	'__process_Require_NodeStruct_Length': function( operation, ofType, hidden ){

		/* get node index by type */
		if (ofType){

			var infoRequireId = this.__process_Require_NodeStructInfo( operation ),

				indexRequireId = this.__process_Require_NodeStruct_Index_Base( operation, true),

				typeRequireId = this.__process_Require_Type( operation, true ),

				requireId = 'node_struct_type_length';

			this.setNodeMarkInfo( operation, 'type_length');

			this.setSimpleSelector_Match_Requirements(

				operation,

				requireId,

				'__code_Get_NodeStruct_Type_Length',

				null,

				[ infoRequireId, indexRequireId, typeRequireId ],

				null,

				requireId,

				false,

				hidden

			);

			return requireId;

		} else {

			return this.__process_Require_NodeStruct_Length_Base( operation, hidden );

		}

	},

	'__process_Require_NodeStruct_Reverse_Index': function( operation, ofType, hidden ){

		var indexRequireId = this.__process_Require_NodeStruct_Index( operation, ofType, true),

			lengthRequireId = this.__process_Require_NodeStruct_Length( operation, ofType, true ),

			requireId = ofType ?

				'node_struct_type_reverse_index'

				:

				'node_struct_reverse_index';

		this.setSimpleSelector_Match_Requirements(

			operation,

			requireId,

			'__code_Get_NodeStruct_Reverse_Index',

			null,

			[ indexRequireId, lengthRequireId ],

			null,

			requireId,

			false,

			hidden

		);

		return requireId;

	},


	'__process_Require_Node_Content_Length': function( operation, hidden ){

		var requireChildNodeStructId = this.__process_Require_ChildNodeStruct_Info( operation, true ),

			requireId = 'node_content_length';

		this.setNodeMarkInfo( operation, 'content_length');

		this.setSimpleSelector_Match_Requirements(

			operation,

			requireId,

			'__code_Get_ChildNodeStruct_Content_Length',

			null,

			[ requireChildNodeStructId ],

			null,

			requireId,

			false,

			hidden

		);

		return requireId;

	},

	'__process_Require_ChildNodeStruct_Info': function( operation, hidden ){

		var requireNodeId = this.__process_Require_ValidNodeId(operation, true),

			requireId = 'child_node_struct_info';

		this.setSimpleSelector_Match_Requirements(

			operation,

			requireId,

			'__code_Get_ChildNodeStructInfo',

			null,

			[ requireNodeId ],

			'__code_PopulateChildNodeInfo',

			null,

			true,

			hidden !== false

		);

		return requireId;

	},


	'__process_Require_RootNode': function( operation, hidden ){

		var requireId = 'root_node',

			ownerRequireId = this.__process_Require_Owner( operation, true );

		this.setSimpleSelector_Match_Requirements(

			operation,

			requireId,

			'__code_Get_RootNodeFromSession',

			null,

			[ ownerRequireId ],

			'__code_Pre_Get_RootNodeFromSession',

			requireId,

			false,

			hidden

		);

		return requireId;

	},

	'__process_Require_Owner': function( operation, hidden){

		var requireId = 'node_owner';

		this.setSimpleSelector_Match_Requirements(

			operation,

			requireId,

			'__code_Get_NodeOwnerFromSession',

			null,

			[],

			'__code_Pre_Get_NodeOwnerFromSession',

			requireId,

			false,

			hidden

		);

		return requireId;

	},

	'__process_Require_ActiveNode': function( operation, hidden ){

		var requireId = 'node_current_active',

			ownerRequireId = this.__process_Require_Owner( operation, true);

		this.setSimpleSelector_Match_Requirements(

			operation,

			requireId,

			'__code_Get_ActiveNodeFromSession',

			null,

			[ ownerRequireId ],

			'__code_Pre_Get_ActiveNodeFromSession',

			requireId,

			false,

			hidden

		);

		return requireId;

	},

	'__process_Require_OwnerHashUrl': function( operation, hidden ){

		var requireId = 'node_current_active',

			ownerRequireId = this.__process_Require_Owner( operation, true);

		this.setSimpleSelector_Match_Requirements(

			operation,

			requireId,

			'__code_Get_OwnerHashFromSession',

			null,

			[ ownerRequireId ],

			'__code_Pre_Get_OwnerHashFromSession',

			requireId,

			false,

			hidden

		);

		return requireId;

	},

	'__process_Require_NodeLanguage': function( operation, hidden ){

		var requireId = 'node_language',

			nodeInfoRequireId = this.__process_Require_AncestorNodeInfo( operation, true );

		this.setNodeMarkInfo( operation, 'node_language');

		this.setSimpleSelector_Match_Requirements(

			operation,

			requireId,

			'__code_Get_NodeLanguageFromNodeInfo',

			null,

			[ nodeInfoRequireId ],

			null,

			requireId,

			false,

			hidden

		);

		return requireId;

	},

	'__process_Require_AncestorNodeInfo': function( operation, hidden ){

		var requireId = 'node_ancestor_node_info',

			validNodeIdRequireId = this.__process_Require_ValidNodeId( operation, true );

		this.setSimpleSelector_Match_Requirements(

			operation,

			requireId,

			'__code_Get_AncestorNodeInfo',

			null,

			[ validNodeIdRequireId ],

			'__code_Pre_Get_AncestorNodeInfo',

			requireId,

			false,

			hidden

		);

		return requireId;

	},

	'__process_Require_Simple_Selector_Validator': function( operation, selector, hidden ){

		var validatorRequireId = this.__Str.dirtyToJsVarname('validator_selector_'+selector),

			sessionRequireId = this.__Str.dirtyToJsVarname('session_selector_'+selector);

		this.setSimpleSelector_Match_Requirements(

			operation,

			validatorRequireId,

			'__code_Get_Simple_Selector_Validator',

			[ selector ],

			[],

			'__code_Pre_Get_Simple_Selector_Validator',

			validatorRequireId,

			false,

			hidden

		);

		this.setSimpleSelector_Match_Requirements(

			operation,

			sessionRequireId,

			'__code_Get_Simple_Selector_Validator_Session',

			[ selector ],

			[ validatorRequireId ],

			'__code_Pre_Get_Simple_Selector_Validator_Session',

			sessionRequireId,

			false,

			hidden

		);

	},

	'__process_AttributeMatch': function( operation, name, operator, value, isExpression ){

		var method = '__code_Match_Attribute[' + operator + ']';

		if ( method in this ){

			var matchId = name+'['+operator+']('+value+')',

				operatorPriorities = this.attributeOperatorPriorities;

			this.setSimpleSelector_Match(

				operation,

				matchId,

				method,

				[ operator, value, isExpression ],

				operator in operatorPriorities ?

					operatorPriorities[ operator ]

					:

					this.defaultAttributeOperatorPriority

			);

			this.__process_Require_Attribute( operation, name );

			if (operator.charAt(0) != '!'){

				this.setNodeDefaultInfo( operation, 'attr_'+name, value );

			}

		} else {

			this.__process_Invalid_Match( operation );

		}

	},

	'__process_Nth_Child_Value': function( value ){

		var cycleSize = 0,

			offset = 0,

			counterIndex = -1,

			len;

		if (Jx.isString(value) && (len = value.length)){

			counterIndex = value.lastIndexOf('n');

			if (value == 'odd'){

				cycleSize = 2;

				offset = 1;

			} else if (value == 'even'){

				cycleSize = 2;


			} else {

				/* has cycleSize */
				if (counterIndex > -1){

					cycleSize = value.substring(0, counterIndex);

					cycleSize = cycleSize.length ?

						cycleSize == '-' ?

							-1

							:

							cycleSize == '+' ?

								1

								:

								parseInt(cycleSize, 10) || 0

						:

						1;

				}

				offset = parseInt(value.substring(counterIndex + 1, len), 10) || 0;

			}

		}

		return [ cycleSize, offset ];

	},

	'__process_Is_Struct_Child': function( operation ){

		this.setSimpleSelector_Match(

			operation,

			'is_child_node_struct',

			'__code_Match_Is_Child_Node_Struct',

			[],

			4,

			null

		);

		this.__process_Require_NodeStructInfo( operation, false );

	},

	'__process_Nth_Child': function(operation, ofType, reverse, expression, symbolIndex, priority){

		this.__process_Is_Struct_Child( operation );

		var constants = this.__process_Nth_Child_Value( expression ),

			cycleSize = constants[0],

			offset = constants[1],

			allow = false;

		/* validate cycleSize and offset */
		if (cycleSize > 0 || offset > 0){

			allow = cycleSize >= 0 || offset > 0;

		}

		if ( allow ){

			var matchId = this.__Str.dirtyToJsVarname( 'nth_child_['+cycleSize.toString()+']['+offset.toString()+']' );

			this.setSimpleSelector_Match(

				operation,

				matchId,

				'__code_Match_Nth_Child',

				[ cycleSize, offset, ofType, reverse ],

				priority,

				null

			);

			/* attach required codes parentNode */
			if (reverse){

				this.__process_Require_NodeStruct_Reverse_Index( operation, ofType );

			} else {

				this.__process_Require_NodeStruct_Index( operation, ofType );

			}

		} else {

			this.__process_Invalid_Match( operation );

		}

	},

	'__process_First_Child': function(operation, nodeVar, ofType, symbolIndex, priority){

		this.__process_Is_Struct_Child( operation );

		this.setSimpleSelector_Match(

			operation,

			ofType ?

				'first_child_of_type'

				:

				'first_child',

			'__code_Match_First_Child',

			[],

			priority,

			null

		);

		this.__process_Require_NodeStruct_Index( operation, ofType );

	},

	'__process_Last_Child': function(operation, nodeVar, ofType, symbolIndex, priority){

		this.__process_Is_Struct_Child( operation );

		this.setSimpleSelector_Match(

			operation,

			ofType ?

				'last_child_of_type'

				:

				'last_child',

			'__code_Match_Last_Child',

			[],

			priority,

			null

		);

		this.__process_Require_NodeStruct_Index( operation, ofType );

		this.__process_Require_NodeStruct_Length( operation, ofType );

	},

	'__process_Only_Child': function(operation, nodeVar, ofType, symbolIndex, priority){

		this.__process_Is_Struct_Child( operation );

		this.setSimpleSelector_Match(

			operation,

			ofType ?

				'only_child_of_type'

				:

				'only_child',

			'__code_Match_Only_Child',

			[],

			priority,

			null

		);

		this.__process_Require_NodeStruct_Index( operation, ofType );

		this.__process_Require_NodeStruct_Length( operation, ofType );

	},


/* Misc */
	'__helper_Get_AttributeDirectAccessExpression': function( nodeVar, name, validate ){

		var directAccess = this.attrNameDirectAccess,

			Str = this.__Str,

			returnValue = { getter: '', setter: ''};


		/* forced direct access */
		if (directAccess.hasOwnProperty( name )){

			returnValue.getter = returnValue.setter = nodeVar+'.'+directAccess[name];

			return returnValue;

		} else if (name == this.nodeQueryIdAttributeName || name == this.nodeQueryIndexAttributeName){

			if (this.dirtyAttrNameRe.test( name )){

				var expression = '"'+ this.__Str.escape(name) + '"';

				returnValue.getter = '(' + expression + ' in '+nodeVar+' ? '+nodeVar+'['+expression+'] : null);'

				returnValue.setter = nodeVar+'.'+name;

			} else {

				returnValue.getter = returnValue.setter = nodeVar+'.'+name;

			}

			return returnValue;

		}

		return void(0);


	},
	'__callback_SimpleSelectorSort': function(a, b){

		var ai = a.priority,

			bi = b.priority,

			J = Jx;

		return !J.isNumber(ai) ?

			1

			:

			!J.isNumber(bi) ?

				-1

				:

				ai - bi;

	},

	'__callback_RegisterPrimaryNodeInfo': function(n, v, o){

		if (o.hasOwnProperty(n)){

			var compiler = this.compiler,

				index = this.nodeInfo,

				names = this.nodeInfoNames,

				current = this.currentSelectorNodeInfo,

				defaults = this.currentSelectorNodeInfoDefaults,

				multiGroupInfoIndex = this.multiGroupNodeInfo,

				cname = 'c_'+n,

				hasInfo = index.hasOwnProperty(n);

			if (!hasInfo){

				names[ names.length ] = n;

				index[ n ] = [];

			}

			if ( defaults.hasOwnProperty( n ) ){

				var currentValues = index[ n ],

					currentValuesCount = currentValues.length,

					defaultValues = defaults[ n ];

				for(var value, c = -1, l = defaultValues.length; l--;){

					if (! (currentValues.lastIndexOf(value = defaultValues[ ++c ]) + 1) ){

						currentValues[ currentValuesCount++ ] = value;

					}

				}

			}

			/* first access */
			if (!(cname in current)){

				multiGroupInfoIndex[ n ] = hasInfo;

				current[cname] = true;

			}

		}

	},


/* Accessors */
	isRegisteredNodeInfo: function( operation, info ){

		return operation.nodeInfo.hasOwnProperty( info );

	},

	isMultiGroupNodeInfo: function( operation, info ){

		var infos = operation.multiGroupNodeInfo;

		return infos.hasOwnProperty( info ) && infos[info];

	},

	getNodeInfoValues: function( operation, info ){

		var index = operation.nodeInfo;

		return index.hasOwnProperty( info ) && index[info];

	},

	hasNodeMarkInfo: function( operation, info ){

		return 'nodeMarkInfos' in operation &&

			Jx.isString(info) &&

			operation.nodeMarkInfos.hasOwnProperty( info );

	},

	hasRequired: function( operation, id ){

		var struct = this.getSimpleSelectorStruct( operation );

		if (struct && Jx.isString(id)){

			var required = struct.required;

			return id in required;

		}

		return false;

	},

	hasSimpleSelectorMatch: function( operation, id ){

		var struct = this.getSimpleSelectorStruct( operation );

		if (struct && Jx.isString(id)){

			var matchIndex = struct.match_index;

			return id in matchIndex;

		}

		return false;

	},

	getSelectorStruct: function(operation){

		return '__selectorStruct' in operation ?

			operation.__selectorStruct

			:

			(operation.__selectorStruct = this.createSelectorStructObject(operation));

	},

	getSimpleSelectorStruct: function(operation){

		return '__simpleSelectorStruct' in operation ?

			operation.__simpleSelectorStruct

			:

			(operation.__simpleSelectorStruct = this.createSimpleSelectorStructObject(operation));

	},

	getSelectorCode: function( operation, query, code ){

		var selectorCodes = 'selectorCodes' in operation && operation.selectorCodes;

		return selectorCodes && selectorCodes.hasOwnProperty(query) ?

			selectorCodes[query]

			:

			void(0);

	},

	getGroupCode: function( operation, query, code ){

		var groupCodes = 'groupCodes' in operation && operation.groupCodes;

		return groupCodes && groupCodes.hasOwnProperty(query) ?

			groupCodes[query]

			:

			void(0);

	},

	getNodeMarkInfosIn: function( operation, infoNames ){

		var J = Jx,

			infos = [],

			infoCount = 0,

			marked = operation && operation.nodeMarkInfos;

		if (J.isString( infoNames )){

			infoNames = [ infoNames ];

		}

		if (J.isArray( infoNames ) && marked){

			for( var name, c=-1, l = infoNames.length; l--; ){

				if (marked.hasOwnProperty( name = infoNames[ ++c ])){

					infos[ infoCount++ ] = name;

				}

			}

		}

		return infos;

	},

	getNodesFrom: function( compiled, subject ){

		/* this is a template method */
		return [];

	},

	setSimpleSelector_Match: function( operation, id, method, params, priority, preprocessor ){

		var struct = this.getSimpleSelectorStruct( operation ),

			matchIndex = struct.match_index,

			matches = struct.matches,

			J = Jx;

		struct.currentSimpleSelectorMatchId = id;

		if (!(id in matchIndex)){

			matches[ matches.length ] = matchIndex[ id ] = {

				id: id,

				method: method,

				precodeMethod: preprocessor,

				params: J.isArray(params) ?

					params

					:

					[],

				requires: [],

				unParameterizedRequires: [],

				priority: J.isNumber( priority ) ?

					priority

					:

					null

			}

		}

		return id;

	},

	setSimpleSelector_Match_Requirements: function(operation, id, method, params, requireParams, precode_method, setToNodeInfo, nullFill, hidden){

		var J = Jx,

			struct = this.getSimpleSelectorStruct( operation ),

			infoIndex = struct.node_info,

			required = struct.required,

			o = void(0);

		if ( J.isString(setToNodeInfo) && setToNodeInfo && !(id in infoIndex) ){

			infoIndex[ id ] = setToNodeInfo;

		}

		if ( !(id in required )){

			required[ id ] = o = {

				id: id,

				method: method,

				params: J.isArray(params) ?

					params

					:

					[],

				requireParams: J.isArray(requireParams) ?

					requireParams

					:

					[],

				nullFill: nullFill === true

			};

			if (precode_method && J.isString(precode_method)){

				o.precode_method = precode_method;

			}

		} else {

			o = required[id];

		}

		if ( hidden !== true ){

			this.attachSimpleSelector_Match_Requirements( operation, struct.currentSimpleSelectorMatchId, id );

		}

		return o;

	},

	setNodeDefaultInfo: function( operation, name, value ){

		var struct = this.getSimpleSelectorStruct( operation );

		if (struct){

			var defaults = struct.node_info_defaults;

			if (!defaults.hasOwnProperty( name ) ){

				defaults[ name ] = [ value ];

			} else {

				var currentDefaults = defaults[name];

				if ( !(currentDefaults.lastIndexOf(name) + 1) ){

					currentDefaults[ currentDefaults.length ] = name;

				}

			}

		}

	},

	attachSimpleSelector_Match_Requirements: function( operation, selectorId, requireId ){

		var struct = this.getSimpleSelectorStruct( operation );

		if ( this.hasSimpleSelectorMatch(operation, selectorId) && this.hasRequired(operation, requireId) ){

			var requires = struct.match_index[ selectorId ].requires;

			requires[ requires.length ] = requireId;

		}

	},

	setNodeMarkInfo: function( operation, info ){

		var nodeMarkInfos = operation.nodeMarkInfos,

			nodeMarkInfoNames = operation.nodeMarkInfoNames;

		if (!nodeMarkInfos){

			nodeMarkInfos = operation.nodeMarkInfos = {};

			nodeMarkInfoNames = operation.nodeMarkInfoNames = [];

		}

		if (Jx.isString(info) && !nodeMarkInfos.hasOwnProperty( info )){

			nodeMarkInfos[

				nodeMarkInfoNames[ nodeMarkInfoNames.length ] = info

			] = true;

		}

	},



/* Misc */
	isValidQuerySubject: function( node ){

		return node !== null && typeof node == 'object' &&

			!!(this.validQueryNodeTypes.lastIndexOf(node.nodeType) + 1);

	},

	isValidFilterSubject: function(nodes){

		return !!nodes && Jx.isNumber( nodes.length );

	},

	createSelectorStructObject: function(operation){

		return {

			simple_selectors: [],

			operators: []

		};

	},

	createSimpleSelectorStructObject: function( operation ){

		return {

			node_info: {},

			node_info_defaults: {},

			required: {},

			match_index: {},

			matches: []

		};

	},

	createRunSession: function( compiledFn ){

		var o = this.$super( arguments );

		o.root = null;

		return o;

	},

	onParse: function(o, operation){

		operation.nodeInfo = {};

		operation.nodeInfoNames = [];

		operation.multiGroupNodeInfo = {};

		this.$super( arguments );

	},

	allowFilter: function(o, selector, nodes, start, limit){

		o.returnValue = [];

		o.trace = this.trace;

		var J = Jx,

			fn = this.compile( selector ),

			valid = o.valid = J.isFunction(fn) && this.isValidFilterSubject(nodes);

		if (valid){

			this.prepareQueryOperation( o, fn, start, limit );

		}

	},

	onFilter: function(o, selector, nodes){

		o.execAfter = true;

		this.onApplyFilter( o, o.compiled, o.session, o.returnValue, o.start, o.limit, nodes );

	},

	onAfterFilter: function(o, selector, node){

		this.destroyRunSession(o.session);

	},

	allowIs: function(o, selector, node){

		o.returnValue = false;

		o.trace = this.trace;

		var fn = o.compiled = this.compile( selector ),

			valid = o.valid = Jx.isFunction(fn) && this.isValidQuerySubject(node);

		if (valid){

			o.session = this.createRunSession( fn );

		}

	},

	onIs: function( o, selector, node ){

		var compiled = o.compiled;

		o.execAfter = true;

		o.returnValue = compiled( o.session, node );

	},

	onAfterIs: function(o, selector, node ){

		this.destroyRunSession(o.session);

	},

	allowSelect: function (o, selector, subject, start, limit ){

		var compiled = this.compile( selector),

			valid = Jx.isFunction( compiled ) && this.isValidQuerySubject( subject );

		if (valid){

			this.prepareQueryOperation( o, compiled, start, limit );

			valid = this.isValidFilterSubject(

				o.nodes = this.getNodesFrom( compiled, subject, o.session )

			);

		}

		o.returnValue = [];

		o.valid = valid;

	},

	onSelect: function( o, selector, subject, start, limit ){

		o.execAfter = true;

		this.onApplyFilter( o, o.compiled, o.session, o.returnValue, o.start, o.limit, o.nodes );

	},

	onAfterSelect: function(o){

		this.destroyRunSession(o.session);

	},

	onApplyFilter: function( o, compiled, session, returnValue, start, limit, nodes ){

		var returnCount = 0,

			inBound = limit || -1;

		for(var n, c=-1, l = nodes.length; l-- && inBound;){

			n = nodes[ ++c ];

			if ( compiled( session, n) ){

				returnValue[ returnCount++ ] = n;

				inBound--;

			}

		}

		if (start > 0){

			returnCount.splice(0, start);

		}

	},

	prepareQueryOperation: function( o, compiled, start, limit ){

		var J = Jx;

		o.start = J.isNumber( start ) && start > -1 ? start : 0;

		if ( J.isNumber(limit) ){

			o.limit = limit > -1 ? limit : 0;

		} else {

			o.limit = o.start;

			o.start = 0;

		}

		o.session = this.createRunSession( o.compiled = compiled );

	},

	purgeSelectorStruct: function(operation){

		if ('__selectorStruct' in operation){

			delete operation.__selectorStruct;

		}

	},

	purgeSimpleSelectorStruct: function( operation ){

		if ('__simpleSelectorStruct' in operation){

			delete operation.__simpleSelectorStruct;

		}

	},

	declare_SelectorMatch: function(operation, struct){

		var selectors = struct.simple_selectors,

			combinators = struct.operators,

			code = 'result = true;';

		for(var selector, combinator, isPrimary, c=-1, l = selectors.length; l--;){

			selector = selectors[++c];

			combinator = combinators[c];

			code = this.declare_SimpleSelectorMatch( operation, 'node', selector, code );

			if (!selector.isPrimary){

				code = this['__code_SelectorCombinator['+combinator+']']( operation, code, selector.source, selector.fullSource );

			}

		}

		return code;

	},

	declare_SimpleSelectorMatch: function( operation, nodeVar, selector, returnCode ){

		var matches = selector.matches,

			required = selector.required,

			isPrimary = selector.isPrimary,

			declared_required = {},

			trailBlocks = [],

			codes = [],

			codeCount = 0,

			Str = this.__Str,

			match, requireParams,

			precodeMethod, params;

		for(var rc, rl, require, c=-1, l = matches.length; l--;){

			match = matches[++c];

			requireParams = [];

			/* declare parameterized required codes */
			this.declare_SimpleSelector_Requirements( operation, nodeVar, required, match.requires, declared_required, codes, isPrimary, requireParams );

			codeCount = codes.length;

			(params = [operation, nodeVar]).push.apply(params, requireParams);

			params.push.apply(params, match.params || [] );

			precodeMethod = match.precodeMethod;

			if (precodeMethod && precodeMethod in this){

				codes[ codeCount++ ] = this[ precodeMethod ].apply( this, params );

			}

			codes[ codeCount++ ] = 'if ('+ this[ match.method ].apply( this, params ) + '){';

			trailBlocks[ trailBlocks.length ] = '}';

		}

		codes[ codeCount++ ] = returnCode;

		codes[ codeCount++ ] = trailBlocks.join('\n');

		return codes.join('\n');

	},

	declare_SimpleSelector_Requirements: function( operation, nodeVar, requireIndex, requireIds, declaredIndex, codes, isPrimary, parameterList ){

		var applyParameters = Jx.isArray( parameterList ),

			parameterCount = applyParameters ?

				parameterList.length

				:

				0,

			Str = this.__Str,

			codeCount = codes.length,

			requireId, requireInfo, symbol,

			defaultValue, nullFill,

			preCodeMethod, code;

		for(var c=-1, l = requireIds.length; l--;){

			requireId = requireIds[++c];

			symbol = this.declare_SimpleSelector_Requirement( operation, nodeVar, requireIndex[ requireId ], requireIndex, declaredIndex, codes, isPrimary );

			if ( applyParameters ){

				parameterList[ parameterCount++ ] = symbol;

			}

		}


	},

	declare_SimpleSelector_Requirement: function( operation, nodeVar, requireInfo, requireIndex, declaredIndex, codes, isPrimary ){

		var Str = this.__Str,

			requireId = requireInfo.id,

			symbol = null,

			preCodeMethod = requireInfo.precode_method,

			preCode, code, codeCount, defaultValue,

			hasSymbolName, sessionSymbolAccess, hasSymbol, myDefaultSymbol,

			params, requireParams, cleanId;

		if ( declaredIndex.hasOwnProperty( requireId ) ){

			symbol = declaredIndex[ requireId ];

		} else if ( requireIndex.hasOwnProperty( requireId ) ){

			requireInfo = requireIndex[ requireId ];

			symbol = declaredIndex[ requireId ] = operation.createRegisterSymbol(

				Str.dirtyToJsVarname( requireInfo.prefix || requireInfo.id || 'unknown' ),

				defaultValue = requireInfo.symbolDefault || null,

				requireInfo.symbolFirst || false,

				requireInfo.symbolNullFill

			);

			/* create parameters and declare other required items if necessary */

			params = [ operation, nodeVar ];

			requireParams = requireInfo.requireParams;

			for(var requireSymbol, requireObj, requireId, subRequireId, paramCount = 2, c=-1, l = requireParams.length; l--;){

				subRequireId = requireParams[++c];

				if ( subRequireId in requireIndex ){

					requireSymbol = this.declare_SimpleSelector_Requirement( operation, nodeVar, requireIndex[subRequireId], requireIndex, declaredIndex, codes, isPrimary );

				} else {

					requireSymbol = 'null';

				}

				params[ paramCount++ ] = requireSymbol;

			}

			params.push.apply( params, requireInfo.params );

			/* generate require code */

			codeCount = codes.length;

			preCode = preCodeMethod && preCodeMethod in this ?

				this[ preCodeMethod ].apply( this, params )

				:

				'';

			code = symbol + '=' + this[ requireInfo.method ].apply( this, params )+';';

			if (isPrimary){

				cleanId = Str.dirtyToJsVarname( requireId );

				hasSymbolName = 'has_'+cleanId;

				sessionSymbolAccess = '"'+Str.escape( 'default_' + requireId )+'"';

				hasSymbol = operation.registerSymbolIf(

					hasSymbolName,

					sessionSymbolAccess +' in session',

					true,

					false

				);

				myDefaultSymbol = this.isMultiGroupNodeInfo( operation, requireId ) &&

					operation.registerSymbolIf(

						'my_'+cleanId,

						hasSymbol + ' && session['+sessionSymbolAccess+']',

						true,

						true

					);

				codes[ codeCount++ ] = 'if ('+hasSymbol+'){';

					codes[ codeCount++ ] = myDefaultSymbol ?

						symbol + ' = '+ myDefaultSymbol + ';'

						:

						symbol + ' = session[' + sessionSymbolAccess + '];';

				codes[ codeCount++ ] = '} else {';

					codes[ codeCount++ ] = preCode;

					codes[ codeCount++ ] = code;

					if (myDefaultSymbol){

						codes[ codeCount++ ] = myDefaultSymbol+' = '+symbol+';';

						codes[ codeCount++ ] = hasSymbol+' = true;'

					}

				codes[ codeCount++ ] = '}';

			} else {

				codes[ codeCount++ ] = preCode;

				codes[ codeCount++ ] = code;

			}

		}



		return symbol;

	},

	declare_GroupSelectors: function( operation, codes ){

		var groups = operation.__groupSelectors,

			l = groups.length,

			codesCount = codes.length;

		operation.multiGroup = l - 1;

		for( var code, c = -1; l--; ){

			code = this.declare_SelectorMatch( operation, groups[ ++c ] );

			/* concurrent selectors */
			if ( c ){

				codes[ codesCount++ ] = 'if (!result){';

					codes[ codesCount++ ] = code;

				codes[ codesCount++ ] = '}';

			/* first */
			} else {

				codes[ codesCount++ ] = code;

			}

		}

		return codes;


	}






});
